<template>
  <a-modal
    title="图片库"
    :width="840"
    :visible="visible"
    :is-loading="loading"
    :mask-closable="false"
    :destroy-on-close="false"
    wrap-class-name="library-modal"
    @cancel="handleCancel"
    @ok="handleSubmit"
  >
    <a-spin :spinning="loading">
      <div class="library-box clearfix">
        <!-- 分组列表 -->
        <div class="file-group">
          <div class="group-tree">
            <a-directory-tree
              v-if="groupListTreeSelect.length"
              :tree-data="groupListTreeSelect"
              :block-node="true"
              :show-icon="true"
              :selected-keys="selectedKeys"
              @select="onSelectGroup"
            ></a-directory-tree>
          </div>
          <a-button class="group-add" type="link" @click="handleAddGroup">新增分组</a-button>
        </div>
        <!-- 文件列表 -->
        <div class="file-list">
          <!-- 头部操作栏 -->
          <div class="top-operate clearfix">
            <a-form-item-rest>
              <!-- 搜索框 -->
              <a-input-search v-model:value="params.fileName" placeholder="搜索文件名称" @search="onSearch" />

              <!-- 上传按钮 -->
              <div class="file-upload">
                <span class="upload-desc">大小不能超过1M</span>
                <a-upload
                  name="file"
                  accept="image/*"
                  :multiple="true"
                  :show-upload-list="false"
                  :before-upload="beforeUpload"
                  :custom-request="onUpload"
                >
                  <a-button>
                    <CloudUploadOutlined />
                    上传
                  </a-button>
                </a-upload>
              </div>
            </a-form-item-rest>
          </div>
          <div class="file-list-body">
            <!-- 文件列表 -->
            <ul v-if="fileList && fileList.length" class="file-list-ul clearfix">
              <li
                v-for="(item, index) in fileList"
                :key="index"
                class="file-item"
                :class="{ active: selectedIndexs.indexOf(index) > -1 }"
                @click="onSelectItem(index)"
              >
                <a-image :src="item.url" :fallback="defaultUrl" :preview="false" />
                <p class="file-name oneline-hide">{{ item.fileName }}</p>
                <div class="select-mask">
                  <CheckOutlined class="selected-icon" />
                </div>
              </li>
            </ul>
            <!-- 无数据时显示 -->
            <a-empty v-else-if="!loading" />
            <!-- 底部操作栏 -->
            <div class="footer-operate clearfix">
              <div v-if="selectedIndexs.length" style="float: left">
                <span class="footer-desc">已选择{{ selectedIndexs.length }}项</span>
                <a-config-provider :auto-insert-space-in-button="false">
                  <a-button-group>
                    <a-button class="btn-mini" size="small" @click="handleDelete()">删除</a-button>
                    <a-button class="btn-mini" size="small" @click="handleBatchMove()">移动</a-button>
                  </a-button-group>
                </a-config-provider>
              </div>
              <!-- 分页组件 -->
              <a-pagination
                v-model="pageInfo.current"
                style="float: right"
                size="small"
                :total="pageInfo.total"
                :page-size="pageInfo.pageSize"
                hide-on-single-page
                @change="handleNextPage"
              />
            </div>
          </div>
        </div>
      </div>
    </a-spin>
    <!-- 新增分组 -->
    <add-group ref="addGroupRef" @reload="getGroupList" />
    <move-group ref="moveGroupRef" @submit="handleRefresh" />
  </a-modal>
</template>

<script name="FileModal" lang="ts" setup>
import type { TreeDataItem } from "ant-design-vue/es/tree";
import { getTree } from "@/api/content/attachGroup";
import { formatTreeSelect } from "@/utils/format";
import { FileSourceEnum, FileTypeEnum } from "@/enums/content";
import type { PaginationConfig } from "@/hooks/useTablePage";
import { cloneDeep } from "lodash-es";
import { delFiles, getPage } from "@/api/content/attachFile";
import { upload } from "@/api/public/common";

const emits = defineEmits(["onFileSelected"]);

const props = defineProps({
  // 多选模式, 如果false为单选
  multiple: {
    type: Boolean,
    default: false
  },
  // 最大选择的数量限制, multiple模式下有效
  maxNum: {
    type: Number,
    default: 100
  },
  // 已选择的数量
  selectedNum: {
    type: Number,
    default: 0
  }
});

const defaultUrl = new URL("./../../../assets/images/default.png", import.meta.url).href;

const visible = ref(false);
const loading = ref(false);

const groupListTree = ref<TreeDataItem[]>([]);
const groupListTreeSelect = ref<TreeDataItem[]>([]);
const selectedKeys = ref<number[]>([-1]);
// 获取文件分组列表
const getGroupList = () => {
  loading.value = true;
  getTree()
    .then(response => {
      const selectItems: TreeDataItem[] = [
        {
          title: "全部",
          key: -1,
          value: -1
        },
        {
          title: "未分组",
          key: 0,
          value: 0
        }
      ];
      groupListTree.value = formatTreeSelect(response.data);
      groupListTreeSelect.value = selectItems.concat(groupListTree.value);
      loading.value = false;
    })
    .catch(error => {
      loading.value = false;
      console.error(error);
    });
};
provide("selectDataSource", groupListTree);

// 搜索表单
const params = reactive({
  groupId: -1,
  // 文件类型: 图片
  fileType: FileTypeEnum.IMAGE.code,
  // 上传来源: 商户后台
  fileSource: FileSourceEnum.MANAGE.code,
  // 文件名称
  fileName: ""
});

// 获取文件列表
const pageInfo = reactive<PaginationConfig>(cloneDeep(defaultPagination));
const paging = reactive({
  current: 1,
  size: 15
});
const fileList = ref([]);

const getFileList = () => {
  loading.value = true;
  getPage(Object.assign(params, paging))
    .then(response => {
      fileList.value = response.data.records;
      pageInfo.total = response.data.total;
      pageInfo.current = response.data.current;
      pageInfo.pageSize = response.data.size;
    })
    .finally(() => {
      loading.value = false;
    });
};

const selectedIndexs = ref<Array<any>>([]);
const handleRefresh = (bool = false) => {
  bool && (paging.current = 1);
  // 清空选中
  selectedIndexs.value = [];
  // 获取文件列表
  getFileList();
};

// 列表分页事件
const handleNextPage = (page: number) => {
  paging.current = page;
  handleRefresh();
};

// 记录选中的文件
const onSelectItem = (index: any) => {
  // 记录选中状态
  if (!props.multiple) {
    selectedIndexs.value = [index];
    return;
  }
  const key = selectedIndexs.value.indexOf(index);
  const selected = key > -1;
  // 验证数量限制
  if (!selected && selectedIndexs.value.length + props.selectedNum >= props.maxNum) {
    antdMessage.warning(`最多可选${props.maxNum}个文件`, 1);
    return;
  }
  !selected ? selectedIndexs.value.push(index) : selectedIndexs.value.splice(key, 1);
};
// 显示
const show = () => {
  getGroupList();
  getFileList();
  visible.value = true;
};

// ---------------分组处理---------------
// 新增分组
const addGroupRef = ref();
const handleAddGroup = () => {
  addGroupRef.value.handleAdd();
};

// 记录选中的分组
const onSelectGroup = (keys: number[]) => {
  params.groupId = keys[0];
  selectedKeys.value = keys;
  handleRefresh(true);
};

// -----------------上传文件---------------
const uploading = ref<Array<any>>([]);
const beforeUpload = (file: any) => {
  const isLt1M = file.size / 1024 / 1024 < 1;
  if (!isLt1M) {
    antdMessage.error("文件大小不能超出1MB");
    return false;
  }
  return true;
};
const onUpload = (info: any) => {
  loading.value = true;
  // 记录上传状态
  uploading.value.push(true);
  const beforeUploadCount = uploading.value.length;
  // 构建上传参数
  const formData = new FormData();
  formData.append("file", info.file);
  // 开始上传
  upload(formData)
    .then(() => {
      setTimeout(() => {
        if (beforeUploadCount === uploading.value.length) {
          uploading.value = [];
          loading.value = false;
          handleRefresh(true);
        }
      }, 10);
    })
    .catch(() => {
      loading.value = false;
    });
};

// ------------------------搜索文件-------------------
const onSearch = () => {
  handleRefresh(true);
};

// ----------------------移动文件分组------------------
// 获取选中的文件
const getSelectedItems = () => {
  const selectedItems: Array<any> = [];
  for (const key in selectedIndexs.value) {
    const index = selectedIndexs.value[key];
    selectedItems.push(fileList.value[index]);
  }
  return selectedItems;
};

// 获取选中的文件id集
const getSelectedItemIds = () => {
  const selectedItems = getSelectedItems();
  return selectedItems.map((item: any) => item.fileId);
};

const moveGroupRef = ref();
const handleBatchMove = () => {
  const fileIds = getSelectedItemIds();
  moveGroupRef.value.show(fileIds);
};

// ----------------------删除文件-------------------
const handleDelete = () => {
  antdModal.confirm({
    title: "您确定要删除该文件吗?",
    icon: createVNode(ExclamationCircleOutlined),
    content: "删除后不可恢复，请谨慎操作",
    onOk() {
      const fileIds = getSelectedItemIds();
      loading.value = true;
      delFiles(fileIds)
        .then(() => {
          handleRefresh();
          antdMessage.success("删除成功");
        })
        .finally(() => {
          loading.value = false;
        });
    }
  });
};

// 关闭
const handleCancel = () => {
  selectedIndexs.value = [];
  visible.value = false;
};

// 确认按钮
const handleSubmit = () => {
  // 获取选中的文件
  const selectedItems = getSelectedItems();
  // 通知父端组件提交完成了
  emits("onFileSelected", selectedItems);
  // 关闭对话框
  handleCancel();
};

defineExpose({ show });
</script>

<style lang="less" scoped>
.library-modal {
  .ant-modal-header {
    border: none;
  }
  .ant-modal-body {
    padding: 6px;
  }

  .ant-empty {
    padding: 120px 0;
  }
}

/* 文件库 */
.library-box {
  user-select: none;

  // 文件分组
  .file-group {
    float: left;
    border-right: 1px solid #e6e6e6;

    // 分组列表
    .group-tree {
      width: 150px;
      height: 440px;
      overflow-y: auto;
      overflow-x: auto;

      .ant-tree {
        display: inline-block;
        min-width: 100%;
        max-height: 380px;
        width: auto;
      }
    }

    // 新增分组
    .group-add {
      display: block;
      margin-top: 20px;
      font-size: 13px;
      padding: 0 30px;
    }
  }

  // 文件列表
  .file-list {
    float: left;
    width: 620px;
    margin-left: 20px;

    // 头部操作区
    .top-operate {
      margin-bottom: 10px;
      .ant-input-search {
        width: 200px;
        float: left;
      }
      .file-upload {
        float: right;
        .upload-desc {
          font-size: 12px;
          padding-right: 10px;
          color: #999;
        }
      }
    }

    // 文件列表
    .file-list-body {
      height: 455px;
      .file-list-ul {
        margin: 0;
        padding: 0;
        height: 417px;
      }

      .file-item {
        width: 105px;
        position: relative;
        cursor: pointer;
        border-radius: 2px;
        padding: 4px;
        border: 1px solid rgba(0, 0, 0, 0.05);
        float: left;
        margin: 8px;
        -webkit-transition: All 0.2s ease-in-out;
        -moz-transition: All 0.2s ease-in-out;
        -o-transition: All 0.2s ease-in-out;
        transition: All 0.2s ease-in-out;
        &:hover {
          border: 1px solid #16bce2;
        }

        :deep(.ant-image) {
          height: 95px;
          width: 95px;
          line-height: 95px;
        }

        :deep(.ant-image-img) {
          height: 95px;
          width: 95px;
        }

        // 文件名称
        .file-name {
          margin-top: 5px;
          font-size: 12px;
          text-align: center;
          padding-bottom: 0px;
          margin-bottom: 0px;
        }

        .oneline-hide {
          white-space: nowrap;
          text-overflow: ellipsis;
          overflow: hidden;
          word-break: break-all;
        }

        // 遮罩层(选中时)
        &.active .select-mask {
          display: block;
        }
        .select-mask {
          display: none;
          position: absolute;
          top: 0;
          bottom: 0;
          left: 0;
          right: 0;
          background: rgba(0, 0, 0, 0.41);
          text-align: center;
          border-radius: 2px;
          .selected-icon {
            font-size: 26px;
            color: #fff;
            line-height: 122px;
            text-align: center;
          }
        }
      }

      // 底部操作栏
      .footer-operate {
        height: 28px;
        margin-top: 10px;
        .footer-desc {
          color: #999;
          margin-right: 10px;
        }
        .btn-mini {
          font-size: 13px;
          padding: 0 15px;
          height: 28px;
        }
      }
    }
  }
}
</style>
